package top.xia17.plugins.fast.auth.register;

import cn.hutool.core.util.StrUtil;
import top.xia17.plugins.fast.common.database.redis.RedisUtils;
import top.xia17.plugins.fast.common.exceptions.BadRequestException;
import top.xia17.plugins.fast.common.mail.Xia17MailUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import top.xia17.plugins.fast.auth.autoconfiguraion.AuthProperties;
import top.xia17.plugins.fast.auth.model.req.UserRegisterReq;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * 邮箱注册验证码发射器
 *
 * @author xia17
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class MailRegisterCodeLauncher implements RegisterCodeLauncher{

    @Override
    public String getId() {
        return "mail";
    }

    private final Xia17MailUtil mailUtil;

    private final RedisUtils redisUtils;

    private final AuthProperties authProperties;

    private Map<String, String> properties;

    /**
     * 邮箱安全认证时的模板参数名称
     */
    private final static String MSG_TEMPLATE_KEY = "msg-template";

    /**
     * 邮箱验证码发送时的标题参数名称
     */
    private final static String SUBJECT_KEY = "subject";

    /**
     * redis前缀的参数名称
     */
    private final static String REDIS_KEY_PREFIX_KEY = "redis-key-prefix";

    /**
     * 限制发送次数的redis前缀的参数名称
     */
    private final static String LIMIT_TAG_REDIS_KEY_PREFIX_KEY = "limit-tag-redis-key-prefix";

    /**
     * 验证码有效时间参数
     */
    private final static String TIME_KEY = "time";

    /**
     * 默认redisKey
     */
    private final static String DEFAULT_REDIS_KEY_PREFIX = "register_code_";

    /**
     * 默认限制发送次数的redis前缀
     */
    private final static String DEFAULT_LIMIT_TAG_REDIS_KEY_PREFIX = "register_code_limit_tag_";

    /**
     * 默认的邮箱验证码模版
     */
    private final static String DEFAULT_MSG_TEMPLATE = "你本次的注册验证码是{code},有效时间10分钟！";


    @Override
    public String send(String tag, String to) {
        RegisterProperties registerProperties = authProperties.getRegister();
        String key = obtainLimitTagRedisKey(tag);
        long expire = redisUtils.getExpire(key);
        if (expire > 0) {
            throw new BadRequestException("请在" + expire + "秒后重试！");
        }
        // 添加标记
        redisUtils.set(key, 1, registerProperties.getSendCodeLimitIntervalTime(), TimeUnit.SECONDS);
        return this.send(to);
    }

    @Override
    public String send(String to) {
        String code = this.generateCode();
        String uuid = this.generateUuid();
        String msgTemplate = this.properties.get(MSG_TEMPLATE_KEY);
        if (StrUtil.isBlank(msgTemplate)) {
            msgTemplate = DEFAULT_MSG_TEMPLATE;
        }
        HashMap<String, String> params = new HashMap<>(4);
        params.put("code", code);
        String content = StrUtil.format(msgTemplate, params);
        mailUtil.send(to, properties.get(SUBJECT_KEY), content, false);
        // 写入redis
        redisUtils.set(obtainRedisKey(uuid), new CodeObj(code, to), obtainCodeEffectiveTime(), TimeUnit.SECONDS);
        return uuid;
    }

    @Override
    public int verify(String uuid, String to, String val) {
        if (StrUtil.isBlank(uuid)) {
            return -1;
        }
        Object code = redisUtils.get(obtainRedisKey(uuid));
        if (code == null) {
            // 无效code
            return -1;
        }
        CodeObj codeObj = (CodeObj) code;
        if (!codeObj.getTo().equals(to)) {
            log.error("注册验证码的使用人不对，应该是{},而目前发现的使用人是{}", codeObj.getTo(), to);
            return -1;
        }
        if (codeObj.getCode().equals(val)) {
            return 1;
        }
        // 验证码错误
        return 0;
    }

    @Override
    public void del(String uuid) {
        redisUtils.del(uuid);
    }

    @Override
    public String getToByReq(UserRegisterReq req) {
        return req.getEmail();
    }

    @Override
    public void setProperties(Map<String, String> properties) {
        this.properties = Objects.requireNonNullElseGet(properties, () -> new HashMap<>(4));
    }

    /**
     * 获取redisKey
     *
     * @param uuid /
     * @return /
     */
    private String obtainRedisKey(String uuid) {
        String prefix = this.properties.get(REDIS_KEY_PREFIX_KEY);
        if (StrUtil.isBlank(prefix)) {
            prefix = DEFAULT_REDIS_KEY_PREFIX;
        }
        return prefix + uuid;
    }

    /**
     * 获取限制标志的redisKey
     *
     * @param tag /
     * @return /
     */
    private String obtainLimitTagRedisKey(String tag) {
        String redisKeyPrefix = properties.get(LIMIT_TAG_REDIS_KEY_PREFIX_KEY);
        if (StrUtil.isBlank(redisKeyPrefix)) {
            return DEFAULT_LIMIT_TAG_REDIS_KEY_PREFIX + tag;
        }
        return redisKeyPrefix + tag;
    }

    /**
     * 获取验证码有效时长
     *
     * @return /
     */
    private long obtainCodeEffectiveTime() {
        String time = properties.get(TIME_KEY);
        if (StrUtil.isBlank(time)) {
            time = "600";
        }
        return Long.parseLong(time);
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    private static class CodeObj {

        /**
         * 验证码
         */
        private String code;

        /** 给谁使用的 */
        private String to;

    }



}
